﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Runtime.Serialization;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace ifunction.Fiddler.Model
{
    /// <summary>
    /// Struct for Schedule
    /// </summary>
    [DataContract]
    public struct Schedule
    {
        #region Constants

        /// <summary>
        /// The XML_ recurrence type
        /// </summary>
        private const string xml_RecurrenceType = "RecurrenceType";

        /// <summary>
        /// The XML_ reference stamp
        /// </summary>
        private const string xml_ReferenceStamp = "ReferenceStamp";

        /// <summary>
        /// The XML_ end stamp
        /// </summary>
        private const string xml_EndStamp = "EndStamp";

        /// <summary>
        /// The string format
        /// {0}: Type
        /// {1}: EndTime
        /// {3}: Reference Time, joined with ';'
        /// </summary>
        private const string stringFormat = "{0}#{1}#{2}";

        /// <summary>
        /// The string regex
        /// </summary>
        private static Regex stringRegex = new Regex(string.Format(stringFormat,
            "<?ScheduleType>([0-9]*)",
            "<?EndTicks>([0-9]*)",
            @"<?RecurrenceTimes>([0-9;\-]*)"), RegexOptions.Compiled | RegexOptions.IgnoreCase);

        #endregion

        /// <summary>
        /// Enum Type
        /// </summary>
        [DataContract]
        public enum ScheduleType
        {
            /// <summary>
            /// The shoot
            /// </summary>
            [EnumMember]
            Shoot = 0,
            /// <summary>
            /// The blood
            /// </summary>
            [EnumMember]
            Blood
        }

        #region Properties

        /// <summary>
        /// Gets or sets the type.
        /// </summary>
        /// <value>The type.</value>
        [DataMember]
        public ScheduleType Type { get; set; }

        /// <summary>
        /// Gets or sets the reference stamp.
        /// </summary>
        /// <value>The reference stamp.</value>
        [DataMember]
        public List<DateTime> ReferenceStamps
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the end stamp.
        /// </summary>
        /// <value>The end stamp.</value>
        [DataMember]
        public DateTime? EndStamp
        {
            get;
            set;
        }

        #endregion

        #region Constuctor

        #endregion

        /// <summary>
        /// Gets the next pin.
        /// </summary>
        /// <param name="nowStandardStamp">The now standard stamp.</param>
        /// <returns>System.Nullable{DateTime}.</returns>
        public DateTime? GetStamp(DateTime nowStandardStamp)
        {
            DateTime? nextStamp = null;



            return nextStamp;
        }

        #region String serialization

        /// <summary>
        /// Returns a <see cref="System.String" /> that represents this instance.
        /// </summary>
        /// <returns>A <see cref="System.String" /> that represents this instance.</returns>
        public override string ToString()
        {
            return string.Format(stringFormat, (int)(this.Type), this.EndStamp == null ? string.Empty : this.EndStamp.Value.Ticks.ToString(), TimeCollectionToString(this.ReferenceStamps));
        }

        /// <summary>
        /// Parses the specified time pin string.
        /// </summary>
        /// <param name="timePinString">The time pin string.</param>
        /// <returns>System.Nullable{Schedule}.</returns>
        public static Schedule? Parse(string timePinString)
        {
            var matchResult = stringRegex.Match(timePinString);
            if (matchResult.Success)
            {
                return new Schedule
                {
                    Type = (ScheduleType)(matchResult.Result("{ScheduleType}").ToInt()),
                    ReferenceStamps = StringToTimeCollection(matchResult.Result("{RecurrenceTimes}")),
                    EndStamp = new DateTime(matchResult.Result("{$EndTicks}").ToLong())
                };
            }

            return null;
        }

        #endregion

        /// <summary>
        /// Converts the UTC automatic local time.
        /// </summary>
        /// <param name="utcDateTime">The UTC date time.</param>
        /// <param name="localTimeZone">The local time zone.</param>
        /// <returns>DateTime.</returns>
        public DateTime ConvertUTCToLocalTime(DateTime utcDateTime, TimeZoneInfo localTimeZone = null)
        {
            return ConvertUTCToLocalTime(utcDateTime, localTimeZone != null ? localTimeZone.BaseUtcOffset.TotalHours : 0);
        }

        /// <summary>
        /// Converts the UTC automatic local time.
        /// </summary>
        /// <param name="utcDateTime">The UTC date time.</param>
        /// <param name="utcOffset">The UTC offset.</param>
        /// <returns>DateTime.</returns>
        public DateTime ConvertUTCToLocalTime(DateTime utcDateTime, double utcOffset)
        {
            var dateTime = new DateTime(
                utcDateTime.Year,
                utcDateTime.Month,
                utcDateTime.Day,
                utcDateTime.Hour,
                utcDateTime.Minute,
                utcDateTime.Second, DateTimeKind.Local);
            dateTime = dateTime.AddHours(utcOffset);

            return dateTime;
        }

        /// <summary>
        /// Times the collection automatic string.
        /// </summary>
        /// <param name="times">The times.</param>
        /// <returns>System.String.</returns>
        private static string TimeCollectionToString(List<DateTime> times)
        {
            List<string> stringList = new List<string>();

            if (times != null)
            {
                foreach (var one in times)
                {
                    stringList.Add(one.ToUtc().ToString("HH-mm"));
                }
            }

            return string.Join(";", stringList);
        }

        /// <summary>
        /// Strings the automatic time collection.
        /// </summary>
        /// <param name="input">The input.</param>
        /// <returns>System.Collections.Generic.List{System.DateTime}.</returns>
        private static List<DateTime> StringToTimeCollection(string input)
        {
            List<DateTime> result = new List<DateTime>();

            if (!string.IsNullOrWhiteSpace(input))
            {
                var times = input.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries);

                if (times != null && times.Length > 0)
                {
                    foreach (var one in times)
                    {
                        var time = one.Split(new char[] { '-' }, StringSplitOptions.RemoveEmptyEntries);
                        if (time.Length == 2)
                        {
                            result.Add(new DateTime(1970, 1, 1, time[0].ToInt(), time[1].ToInt(), 0, DateTimeKind.Utc));
                        }
                    }
                }
            }

            return result;
        }

    }
}
